package com.mazaiting.redeye.utils;

import android.util.Base64;
import com.mazaiting.log.L;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/***
 *
 *
 *                                                    __----~~~~~~~~~~~------___
 *                                   .  .   ~~//====......          __--~ ~~
 *                   -.            \_|//     |||\\  ~~~~~~::::... /~
 *                ___-==_       _-~o~  \/    |||  \\            _/~~-
 *        __---~~~.==~||\=_    -_--~/_-~|-   |\\   \\        _/~
 *    _-~~     .=~    |  \\-_    '-~7  /-   /  ||    \      /
 *  .~       .~       |   \\ -_    /  /-   /   ||      \   /
 * /  ____  /         |     \\ ~-_/  /|- _/   .||       \ /
 * |~~    ~~|--~~~~--_ \     ~==-/   | \~--===~~        .\
 *          '         ~-|      /|    |-~\~~       __--~~
 *                      |-~~-_/ |    |   ~\_   _-~            /\
 *                           /  \     \__   \/~                \__
 *                       _--~ _/ | .-~~____--~-/                  ~~==.
 *                      ((->/~   '.|||' -_|    ~~-/ ,              . _||
 *                                 -_     ~\      ~~---l__i__i__i--~~_/
 *                                 _-~-__   ~)  \--______________--~~
 *                               //.-~~~-~_--~- |-------~~~~~~~~
 *                                      //.-~~~--\
 *                               神兽保佑
 *                              代码无BUG!
 * @author mazaiting
 * @date 2019-06-20
 * @decription RSA 加解密, 依赖 commons-codec 库
 */
public class Rsa {
    /**
     * 公钥
     */
//    private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKM46QBmkIua4eHVdczKBZPAhWDaoJTFhh68KFuym7LXdsOUX87fSJvWhCs5LpgyQEeUNzB+c6uo6lgDhAnGi+B9py1903/agbwWWmzw+7INpQib9qTpnkus3FWU1GdPmvMOOcj5DB0jOR6Z5gpHmqtZzQjttEA9quhWfYuy6eXwIDAQAB";
    /**
     * 字节数据转字符串专用集合
     */
    private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /**
     * 私钥
     */
    private RSAPrivateKey mPrivateKey;

    /**
     * 公钥
     */
    private RSAPublicKey mPublicKey;

    /**
     * 构造方法
     * @param publicKey 公钥
     */
    public Rsa(String publicKey) {
        try {
            loadPublicKey(publicKey);
            L.d("加载公钥成功");
        } catch (Exception e) {
            L.d(e.getMessage());
        }
        try {
            loadPrivateKey("");
            L.d("加载私钥成功");
        } catch (Exception e) {
            L.d(e.getMessage());
        }
    }

    /**
     * RSA 加密数据
     * @param data 待加密数据
     * @return 加密后数据
     */
    public String encrypt(String data) throws Exception {
        if (null == mPublicKey) {
            throw new Exception("加密公钥为空, 请设置");
        }
        Cipher cipher;
        try {
            // 获取密文实例
            cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
            // 使用公钥和加密模式
            cipher.init(Cipher.ENCRYPT_MODE, mPublicKey);

            // 加密
            return Base64.encodeToString(cipher.doFinal(data.getBytes()), Base64.DEFAULT);
        } catch (NoSuchPaddingException e) {
            throw new Exception("NoSuchPaddingException");
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此加密算法");
        } catch (InvalidKeyException e) {
            throw new Exception("加密公钥非法,请检查");
        } catch (BadPaddingException e) {
            throw new Exception("明文数据已损坏");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("明文长度非法");
        }
    }

    /**
     * RSA 解密数据
     * @param data 待解密数据
     * @return 解密后数据
     */
    public String decrypt(String data) throws Exception {
        if (null == mPrivateKey) {
            throw new Exception("解密私钥为空, 请设置");
        }
        Cipher cipher;
        try {
            // 获取密文实例
            cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
            // 使用私钥和解密模式
            cipher.init(Cipher.DECRYPT_MODE, mPrivateKey);
            // 解密
            return new String(cipher.doFinal(Base64.decode(data, Base64.DEFAULT)));
        } catch (NoSuchPaddingException e) {
            throw new Exception("NoSuchPaddingException");
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此解密算法");
        } catch (InvalidKeyException e) {
            throw new Exception("解密私钥非法,请检查");
        } catch (BadPaddingException e) {
            throw new Exception("明文数据已损坏");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("明文长度非法");
        }
    }


    /**
     * 字节数据转十六进制字符串
     * @param data 二进制数据
     * @return 十六进制内容
     */
    private String byteArrayToString(byte[] data) {
        // 创建字符串构造器
        StringBuilder builder = new StringBuilder();
        // 遍历
        for (byte b : data) {
            // 取出字节高四位,作为索引得到相应的十六进制标识符，注意无符号右移
            builder.append(HEX_CHAR[(b & 0xf0) >>> 4]);
            // 取出字节低四位,作为索引得到相应的十六进制标识符
            builder.append(HEX_CHAR[(b & 0x0f)]);
//            if (i < data.length - 1) {
//                builder.append(' ');
//            }
        }
        return builder.toString();
    }

    /**
     * 加载公钥
     *
     * @param publicKey 公钥
     * @throws Exception 加载公钥时产生的异常
     */
    private void loadPublicKey(String publicKey) throws Exception {
        try {
//            BASE64Decoder base64Decoder = new BASE64Decoder();
//            byte[] buffer = base64Decoder.decodeBuffer(publicKey);
            byte[] buffer = Base64.decode(publicKey, Base64.DEFAULT);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
            mPublicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
//        } catch (IOException e) {
//            throw new Exception("公钥数据内容读取错误");
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此算法");
        } catch (InvalidKeySpecException e) {
            throw new Exception("公钥非法");
        } catch (NullPointerException e) {
            throw new Exception("公钥数据为空");
        }
    }

    /**
     * 加载私钥
     *
     * @param privateKey 私钥
     * @throws Exception 加载私钥时产生的异常
     */
    private void loadPrivateKey(String privateKey) throws Exception {
        try {
//            Base64 base64 = new Base64();
//            // 创建 Base64 解码器
//            BASE64Decoder base64Decoder = new BASE64Decoder();
//            // 将字符串私钥解码为字节数组
//            byte[] buffer = base64Decoder.decodeBuffer(privateKey);
            byte[] buffer = Base64.decode(privateKey, Base64.DEFAULT);
            // 创建 PKCS8 格式的 KEY
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
            // 获取 RSA 算法钥匙工厂
            KeyFactory factory = KeyFactory.getInstance("RSA");
            // 生成私钥
            mPrivateKey = (RSAPrivateKey) factory.generatePrivate(keySpec);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此算法");
        } catch (InvalidKeySpecException e) {
            System.out.println(e.getMessage());
            throw new Exception("私钥非法");
//        } catch (IOException e) {
//            throw new Exception("私钥数据内容读取错误");
        } catch (NullPointerException e) {
            throw new Exception("私钥数据为空");
        }
    }
}
